/**
 * @copyright 2017 sinping.com 北京芯平科技股份有限公司. All rights reserved.
 * 本内容仅限于北京芯平科技股份有限公司内部传阅，禁止外泄以及用于其他的商业目的.
 */
package com.sinping.qh.api.filter;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.sinping.qh.api.support.Const;
import com.sinping.qh.api.support.ConstEum;
import com.sinping.qh.api.support.ResDto;
import com.sinping.qh.domain.auth.Token;
import com.sinping.qh.domain.auth.User;
import com.sinping.qh.dto.auth.UserSessionDTO;
import com.sinping.qh.repository.mongo.user.UserLaboratoryRepository;
import com.sinping.qh.service.auth.ISessionService;
import com.sinping.qh.service.auth.ITokenService;
import com.sinping.qh.service.auth.IUserService;
import com.sinping.qh.utils.auth.AuthUtil;
import com.sinping.qh.utils.mapper.JsonMapper;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;
import java.util.Map;

/**
 * @author guojie
 * @create 2017/12/21
 */
public class AuthFilter implements Filter {

    private final static Logger log = LoggerFactory.getLogger(AuthFilter.class);
    public static final String token_name = "token";


    @Autowired
    private ISessionService sessionService;

    @Autowired
    private ITokenService iTokenService;
    @Autowired
    private IUserService userService;

    private FilterConfig filterConfig;
    @Autowired
    UserLaboratoryRepository userLaboratoryRepository;
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        ResDto resDto = new ResDto();
        HttpServletRequest r = (HttpServletRequest) request;
        HttpServletResponse q = (HttpServletResponse) response;
        String token = this.retriveParaFromHeaderOrRquest(request, token_name);
        //String permission= this.retriveParaFromHeaderOrRquest(request,perm_name);
        String requestURI = r.getRequestURI();
        String urlApi = this.getUrlApi(requestURI);
        String requestMethod = r.getMethod();//
        if (!StringUtils.isEmpty(token) && !"".equals(token.trim())) {
            //验证通过
        } else {
            resDto.setStatus(Const.UNAUTHORIZED);
            resDto.setMsg("请重新登录");
            this.sendJsonMessage(request, response, resDto);
            return;
        }
        UserSessionDTO sessionByToken = sessionService.getSessionByToken(token);
        if (sessionByToken == null) {
            EntityWrapper<Token> tokenEntityWrapper = new EntityWrapper<Token>();
            Token tokenSelect = new Token();
            tokenSelect.setToken(token);
            tokenEntityWrapper.setEntity(tokenSelect);
            Token get = iTokenService.selectOne(tokenEntityWrapper);
            if (get == null) {
                //用户去登陆  提示信息
                resDto.setStatus(Const.UNAUTHORIZED);
                resDto.setMsg("请重新登录");
                this.sendJsonMessage(request, response, resDto);
                return;
            } else {
                // token 创建 redis 对象
                User user=userService.selectById(get.getUserId());

                // 新建授权对象
                UserSessionDTO sessionByTokenNew = sessionService.createSessionByToken(token, user);
                if (sessionByTokenNew != null) {
                    int i = sessionService.saveSessionToRedis(sessionByTokenNew);
                    Token upDatetoken = new Token();
                    upDatetoken.setId(get.getId());
                    upDatetoken.setUpdateTime(new Date());
                    // 用户登录 增加 次数
                    if (get.getTokenLoginTimes() == null) {
                        upDatetoken.setTokenLoginTimes(1);
                    } else {
                        upDatetoken.setTokenLoginTimes(new Integer(get.getTokenLoginTimes()) + 1);
                    }
                   try {
                       boolean b = iTokenService.updateById(upDatetoken);
                   } catch (Exception e){
                        e.printStackTrace();
                       log.debug("token 更新失败 token:{}",token);
                   }
                    //  建权成功
                    sessionByToken = sessionByTokenNew;

                } else {
                    //redis授权失败
                    resDto.setStatus(Const.FORBIDDEN);
                    log.debug("redis授权失败 token:{}",token);
                    resDto.setMsg("msg.no.auth");
                    this.sendJsonMessage(request, response, resDto);
                    return;
                }
            }
        }
        //此情况 不应出现
        if (sessionByToken == null) {
            resDto.setStatus(Const.SERVER_ERROR);
            resDto.setMsg(ConstEum.SERVER_ERROR.getMessage());
            this.sendJsonMessage(request, response, resDto);
            return;
        }
        boolean validate = this.validate(sessionByToken, urlApi, requestMethod);
        //TODO 先改为true ,配置完资源后再恢复
        if (validate) {
//        if (true) {
            chain.doFilter(request, response);
        } else {
            //验权失败
            resDto.setStatus(Const.FORBIDDEN);
            resDto.setMsg("没有访问权限");
            this.sendJsonMessage(request, response, resDto);
            return;
        }
    }

    /**
     * 判断url 是否 授权
     * true 成功 ；false 失败
     *
     * @return
     */
    private boolean validate(UserSessionDTO sessionByToken, String url, String requestMethond) {
        Map<String, String[]> urlResoure = sessionByToken.getUrlResoure();
        String[] perms = urlResoure.get(url);
        if (perms != null) {
            for (int i = 0; i < perms.length; i++) {
                if (perms[i].equals(requestMethond)) {
                    return true;
                }
                ;
            }
        }
        return false;
    }

    private String getUrlApi(String apiPath) {
        int api = apiPath.indexOf("api");
        String substring = apiPath.substring(api - 1, apiPath.length());
        String formatUrl = AuthUtil.formatUrl(substring, Const.placeHolder);
        return formatUrl;
    }

    private void sendJsonMessage(ServletRequest request, ServletResponse response, ResDto resDto) {
        try {
            HttpServletRequest httpServletRequest = (HttpServletRequest) request;
            HttpServletResponse httpServletResponse = (HttpServletResponse) response;
            httpServletResponse.setCharacterEncoding("UTF-8");
            httpServletResponse.setContentType("application/json");
            httpServletResponse.getWriter().write(JsonMapper.defaultMapper().toJson(resDto));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void destroy() {
        this.filterConfig = null;
    }

    private String retriveParaFromHeaderOrRquest(ServletRequest request, String param) {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        String header = httpServletRequest.getHeader(param);
        if (StringUtils.isEmpty(header)) {
            return httpServletRequest.getParameter(param);
        } else {
            return header;
        }
    }
}
